/**
 * Copyright (c) 2018-2028, HQY 胡庆一 (215218393@qq.com).
 * <p>
 * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.gnu.org/licenses/lgpl.html
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.ocm.order.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator;
import com.ocm.common.constant.OrderAfterStatusConstant;
import com.ocm.common.constant.OrderStatusConstant;
import com.ocm.core.log.exception.ServiceException;
import com.ocm.core.mp.support.Condition;
import com.ocm.core.tool.api.R;
import com.ocm.core.tool.utils.BeanUtil;
import com.ocm.core.tool.utils.DateUtil;
import com.ocm.order.dto.*;
import com.ocm.order.service.IOrderDetailService;
import com.ocm.order.vo.*;
import com.ocm.order.dto.*;
import com.ocm.order.entity.Order;
import com.ocm.order.entity.OrderAfter;
import com.ocm.order.entity.OrderDetail;
import com.ocm.order.service.IOrderAfterService;
import com.ocm.order.vo.*;
import com.ocm.order.mapper.OrderMapper;
import com.ocm.order.service.IOrderService;
import com.ocm.core.mp.base.BaseServiceImpl;
import com.ocm.pay.bo.PayOrderBO;
import com.ocm.pay.bo.RefundOrderBO;
import com.ocm.pay.feign.IPayClient;
import com.ocm.product.feign.ISpuClient;
import com.ocm.shop.entity.Shop;
import com.ocm.shop.feign.IShopClient;
import com.ocm.warehouse.bo.StockLockBO;
import com.ocm.warehouse.bo.StockLockItemsBO;
import com.ocm.warehouse.feign.IStockClient;
import com.ocm.warehouse.to.StockUnlockTO;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ThreadPoolExecutor;

import static com.ocm.common.constant.OrderStatusConstant.*;
import static com.ocm.pay.constant.PayTypeConstant.PAY_TYPE_SHOP;
import static com.ocm.pay.constant.PayTypeConstant.PAY_TYPE_USER;

/**
 *  服务实现类
 *
 * @author HQY
 * @since 2022-01-16
 */
@Service
public class OrderServiceImpl extends BaseServiceImpl<OrderMapper, Order> implements IOrderService {

	@Resource
	ISpuClient spuClient;

	@Resource
	IOrderDetailService orderDetailService;

	@Resource
	IOrderAfterService orderAfterService;

	@Resource
	IStockClient stockClient;

	@Resource
	ThreadPoolExecutor executor;

	@Resource
	RabbitTemplate rabbitTemplate;

	@Resource
	IShopClient shopClient;

	@Resource
	IPayClient payClient;

	private final DefaultIdentifierGenerator idGenerator=new DefaultIdentifierGenerator();

	@Override
	public UOrderDetailVO getOrderDetail(Order order) {
		UOrderDetailVO detail =new UOrderDetailVO();
		Order one = this.getOne(Condition.getQueryWrapper(order));
		detail.setOrder(one);
		detail.setItems(orderDetailService.list(new QueryWrapper<OrderDetail>().eq("order_id",order.getId())));
		R<Shop> res = shopClient.shopInfo(one.getShopId());
		if(!res.isSuccess()){
			throw new ServiceException(res.getMsg());
		}
		detail.setShop(BeanUtil.copy(res.getData(), OrderShopVO.class));
		return detail;
	}


	@Override
	public void orderAfterRefund(Long id, Long shopId) {
			try {
				OrderAfter orderAfter = orderAfterService.getById(id);
				//发起退款
				this.refund(new RefundDTO(orderAfter.getOrderId(),orderAfter.getAmount()),shopId,id);
			}catch (Exception e){
				throw new ServiceException(e.getMessage());
			}

	}

	/**
	 * 发货
	 * @param deliverDTO
	 * @param shopId
	 */
	@Override
	@Transactional
	public void deliver(DeliverDTO deliverDTO, Long shopId) {
		Order order = new Order();
		order.setId(deliverDTO.getId());
		order.setLogistics(deliverDTO.getLogistics());
		order.setStatus(ORDER_STATUS_DELIVER);
		order.setDeliverTime(DateUtil.now());

		if(baseMapper.update(order,new UpdateWrapper<Order>().eq("id",order.getId()).eq("status",ORDER_STATUS_PAID))>0){
			//自动收货队列
			rabbitTemplate.convertAndSend("received-event-exchange","received.create.received",order.getId());

			//库存扣减队列
			rabbitTemplate.convertAndSend("received-event-exchange","received.stock.received",order.getId());
		}else{
			throw new ServiceException("订单状态改变,发货失败");
		}

	}

	/**
	 * 已支付/未发货---->退款
	 * @param
	 */
	@Override
	@GlobalTransactional
	@Transactional(rollbackFor = Exception.class)
	public void refund(Long orderId,Long userId) {
		Order order = new Order();

		order.setStatus(ORDER_STATUS_SHUTDOWN);
		order.setFinalTime(DateUtil.now());
		UpdateWrapper<Order> w = new UpdateWrapper<Order>()
			.eq("id",orderId)
			.eq("status", ORDER_STATUS_PAID);

		if(userId!=null){
			w.eq("create_user",userId);
		}

		if(baseMapper.update(order,w)>0){

			R res=stockClient.stockUnLock(orderId);
			if(!res.isSuccess()){
				throw new ServiceException(res.getMsg());
			}
			res = payClient.refund(new RefundOrderBO(null, orderId, null));
			if(!res.isSuccess()){
				throw new ServiceException(res.getMsg());
			}
			/**
			 * 发送信息 解锁库存
			 */
			//rabbitTemplate.convertAndSend("order-event-exchange","order.release.other",new StockUnlockTO(orderId));
		}else{
			throw new ServiceException("订单状态已经改变,请刷新页面");
		}
	}

	/**
	 * 已发货 售后退款
	 * @param refundDTO 订单Id 退款金额
	 * @param shopId 店铺Id
	 */
	@Override
	@Transactional
	public void refund(RefundDTO refundDTO,@Nullable Long shopId,Long afterOrderId) {

		Order order = new Order();
		order.setStatus(ORDER_STATUS_AFTER_SHUTDOWN);
		order.setUpdateTime(DateUtil.now());
		order.setFinalTime(DateUtil.now());

		UpdateWrapper<Order> w = new UpdateWrapper<Order>()
			.eq("id", refundDTO.getOrderId())
			.in("status", ORDER_STATUS_REFUND_GOODS,ORDER_STATUS_REFUND);

		if(shopId!=null){
			w.eq("shop_id",shopId);
		}

		if(this.update(order,w)){

			//更改售后单为完成状态
			if(afterOrderId!=null){
				if(!orderAfterService.update(new UpdateWrapper<OrderAfter>()
					.eq("id",afterOrderId)
					.in("status",OrderAfterStatusConstant.WAIT_DISPOSE,OrderAfterStatusConstant.WAIT_DISPOSE_SEND_BACK)
					.set("status", OrderAfterStatusConstant.FINISH)
					.set("finish_time",DateUtil.now())
				)){
					throw new ServiceException("售后状态改变,请刷新");
				}
			}

			R res = payClient.refund(new RefundOrderBO(refundDTO.getAmount(), refundDTO.getOrderId(), null));
			if(!res.isSuccess()){
				throw new ServiceException(res.getMsg());
			}

		}else{
			throw new ServiceException("订单状态已经改变,请刷新页面");
		}
	}

	@Override
	public Integer getStatusById(Long orderId) {
		return baseMapper.getStatusById(orderId);
	}

	@Override
	@Transactional
	public Boolean uPay(OrderPayDTO orders, Long userId, String userName) {

		/**
		 * 支付成功采用rabbitmq通知的方式 此处没有支付成功修改订单的操作 仅调用支付服务
		 */
		for (Long id : orders.getOrderIds()){

			Order o = this.getById(id);
			R<Shop> shopR = shopClient.shopInfo(o.getShopId());
			if(!shopR.isSuccess()){
				throw new ServiceException(shopR.getMsg());
			}
			Shop s =shopR.getData();

			//校验订单是否可交易
			if(s.getStatus()!=1){
				throw new ServiceException("该店铺被禁止交易");
			}
			if(o.getStatus()!=ORDER_STATUS_UNPAID){
				if(o.getStatus()==ORDER_STATUS_SHUTDOWN)
					throw new ServiceException("该订单已关闭");
				throw new ServiceException("该订单状态不允许此操作");
			}


			//调用支付服务
			R res = payClient.deal(
				new PayOrderBO(userId, userName, PAY_TYPE_USER,
					s.getId(), s.getShopName(), PAY_TYPE_SHOP,
					o.getFinalPrice(),
					o.getId(), "购买商品",
					orders.getCardId(), orders.getBankType(), orders.getBankCard(), orders.getCardType(),
					orders.getPayPassword(), null)
			);
			//判断交易是否成功
			if(!res.isSuccess()){
				throw new ServiceException(res.getMsg());
			}
		}
		return true;
	}

	@Override
	public IPage<OrderVO> selectOrderPage(IPage<OrderVO> page, OrderVO order) {
		return page.setRecords(baseMapper.selectOrderPage(page, order));
	}

	@Override
	public IPage<UOrderVO> uList(IPage<UOrderVO> page, Long userId, Integer status) {
		List<UOrderVO> orderVOS = baseMapper.uList(page, userId, status);
		for(UOrderVO o:orderVOS){
			o.setItems(orderDetailService.selectItemsByOrderId(o.getId()));
		}
		return page.setRecords(orderVOS);
	}

	/**
	 * 收货
	 * @param orderId 订单号
	 * @param userId 用户id
	 */
	@Override
	@Transactional
	public void receiving(Long orderId,@Nullable Long userId) {
		Order order = new Order();
		order.setStatus(OrderStatusConstant.ORDER_STATUS_RECEIVED);
		order.setFinalTime(DateUtil.now());

		UpdateWrapper<Order> w = new UpdateWrapper<Order>()
			.eq("id", orderId)
			.eq("is_deleted", 0);
		if(userId!=null){
			w.eq("create_user",userId);
		}
		if(!this.update(order,w)){
			throw new ServiceException("操作失败");
		}
		R res=payClient.receiving(orderId);
		if(!res.isSuccess()){
			throw new ServiceException(res.getMsg());
		}


	}

	@Override
	public Integer getOrderStatus(Long id) {
		return baseMapper.getOrderStatus(id);
	}

	@Override
	@Transactional
	public OrderPayVO create(OrderDTO orderDTO) {
		//购物项数据
		List<OrderItemDTO> items = orderDTO.getItems();
		//地址数据
		OrderAddressDTO address = orderDTO.getAddress();
		//订单id
		Long id = idGenerator.nextId(null);

		//库存锁定列表 传输至仓库服务
		List<StockLockItemsBO> stockLockList=new ArrayList<>(16);
		//订单详情数据
		List<OrderDetail> orderDetailList = new ArrayList<>(16);

		//设置主键
		Order order = BeanUtil.copy(address,Order.class);
		order.setId(id);

		//设置订单备注
		order.setOrderRemark(orderDTO.getOrderRemark());

		Long shopId = null;

		BigDecimal postage=new BigDecimal(0);
		BigDecimal price=new BigDecimal(0);

		//获取购物项数据
		for(OrderItemDTO o:items){

			R<OrderDetailDTO> orderData = spuClient.getOrderData(o.getSkuId());

			if(!orderData.isSuccess()){
				throw new ServiceException(orderData.getMsg());
			}

			OrderDetailDTO orderDetailDTO =orderData.getData();

			//设置件数
			orderDetailDTO.setSkuCount(o.getCount());
			//设置最终价格
			orderDetailDTO.setFinalPrice(orderDetailDTO.getSkuPrice());

			//价格合计计算 + 单价*件数
			price=price.add(orderDetailDTO.getSkuPrice().multiply(BigDecimal.valueOf(o.getCount())));
			//邮费计算
			postage=postage.add(orderDetailDTO.getSpuPostage());
			//设置订单id
			orderDetailDTO.setOrderId(id);
			//将信息添加
			orderDetailDTO.setId(idGenerator.nextId(orderDetailDTO));
			orderDetailList.add(orderDetailDTO);

			//库存锁定信息添加
			stockLockList.add(new StockLockItemsBO(orderDetailDTO.getSkuId(),o.getCount()));

			//校验订单项是否应属于同一订单
			if(shopId==null){
				shopId=orderDetailDTO.getShopId();
				order.setShopId(shopId);
				continue;
			}
			if(!orderDetailDTO.getShopId().equals(shopId)){
				throw new ServiceException("子订单不属于同一商家");
			}


		}

		R<Long> res = stockClient.stockLock(new StockLockBO(order.getId(), stockLockList));
		if(!res.isSuccess()){
			throw new ServiceException(res.getMsg());
		}
		//锁定库存
		Long skuId = res.getData();
		if(!skuId.equals(0L)){
			for(OrderDetail o:orderDetailList){
				if(o.getSkuId().equals(skuId)){
					throw new ServiceException("商品:"+o.getSpuTitle()+"库存不足!");
				}
			}
			throw new ServiceException("下单失败,服务器超时,稍后重试");
		}

		//客户端发过来的订单价格
		BigDecimal sumPrice = orderDTO.getPrice();

		//设置价格等信息
		double abs = Math.abs(sumPrice.subtract(price.add(postage)).doubleValue());
		//对价
		if(abs>=0.01){
			throw new ServiceException("有商品价格出现变动,请重新下单");
		}
		//初始价格
		order.setInitialPrice(price);
		//总邮费
		order.setOrderPostage(postage);
		//减免价格 todo 暂不设置
		order.setDeratePrice(new BigDecimal(0));
		//最终价格
		order.setFinalPrice(sumPrice);

		//保存数据
		this.save(order);
		orderDetailService.saveBatch(orderDetailList);
		rabbitTemplate.convertAndSend("order-event-exchange","order.create.order",order.getId());
		return new OrderPayVO(order.getId(),sumPrice);
	}
}
